<template>
	<div :class="[layoutClass]">
		<div
			ref="wrapper"
			v-loading="gridReload"
			:class="{ 'has-gridlines': props.defineConfig.hasGrid }"
		>
			<!-- @layout-updated="layoutUpdated" -->
			<GridLayout
				v-if="!gridReload"
				ref="gridLayout"
				v-model:layout="layout"
				:row-height="rowHeight"
				:col-num="colNum"
				:margin="margin"
				:cols="colsConfig"
				:responsive-layouts="presetLayouts"
				responsive
				:style="bgStyle"
				@click="layoutClick"
			>
				<GridItem
					v-for="item in layout"
					:x="item.x"
					:y="item.y"
					:w="item.w"
					:h="item.h"
					:i="item.i"
					:key="item.i"
					:colNum="colNum"
					@moved="moved"
					@resized="resized"
					@click.stop="itemClick(item)"
				>
					<div
						:class="[
							'grid-item',
							{ 'active-item': item.i === storeTarget.currentId }
						]"
					>
						<el-icon
							v-if="item.i === storeTarget.currentId"
							class="delete-icon"
							@click="optLayout(item, 'filter')"
						>
							<DeleteFilled />
						</el-icon>
						<el-icon
							v-if="item.i === storeTarget.currentId"
							class="copy-icon"
							@click="copyLayout(item)"
						>
							<CopyDocument />
						</el-icon>
						<div v-if="item.children.length < 1" class="nodata-tips">
							<div class="nodata-content">
								<el-icon class="nodata-icon"><DocumentAdd /></el-icon>
								可以从左侧拖入组件
							</div>
						</div>
						<template v-else>
							<component
								v-for="(comp, index) in item.children"
								:is="comp.category"
								:key="comp.category + '_' + index"
								:options="comp"
								:is-design="true"
								@operation="operationItem"
							/>
						</template>
					</div>
				</GridItem>
			</GridLayout>
		</div>
	</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, nextTick, onMounted, toRef } from 'vue'
import { useLayoutStore } from '@/store/modules/layout'
import { useTargetStore } from '@/store/modules/target'
import { useHistoryStore } from '@/store/modules/history'
import {
	DocumentAdd,
	DeleteFilled,
	CopyDocument
} from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'

const store = useLayoutStore()
const storeTarget = useTargetStore()
const historyStore = useHistoryStore()
const colsConfig = ref({})
const gridReload = ref(false)
const props = defineProps({
	defineConfig: {
		type: Object,
		default: () => {
			return {
				layoutType: 'PC',
				hasGrid: true
			}
		}
	}
})

const layoutType = computed(() => {
	return props.defineConfig.layoutType
})

const pageSize = computed(() => {
	return layoutType.value === 'PC'
		? 'lg'
		: layoutType.value === 'PAD'
		? 'sm'
		: 'xxs'
})

const layoutClass = computed(() => {
	return layoutType.value + '-layout'
})

const rowHeight = computed(() => {
	return store.rowHeight
})

const colNum = computed(() => {
	return store.colNum[pageSize.value]
})

const margin = computed(() => {
	return store.getMargin
})

const bgStyle = ref(null)

// 当前布局数据
const layout = ref([])

// 不同分辨路时对应的数据
const presetLayouts = ref({
	lg: [],
	sm: [],
	xxs: []
})

const layoutChenged = (newCol, oldCol) => {
	const rote = newCol / oldCol
	Object.keys(presetLayouts.value).forEach((ac) => {
		presetLayouts.value[ac].forEach((item) => {
			item.w = Math.floor(item.w * rote)
			item.x = Math.floor(item.x * rote)
		})
	})
	layout.value = presetLayouts.value[pageSize.value]
	nextTick(() => {
		gridReload.value = false
	})
}

const copyLayout = (dragItem: any) => {
	const i = 'dropId' + new Date().getTime()
	const item = {
		name: dragItem.name,
		x: dragItem.x,
		y: dragItem.y,
		w: dragItem.w,
		h: dragItem.h,
		i,
		category: dragItem.category,
		children: []
	}
	optLayout(item, 'push')
}

// 操作布局数据
const optLayout = (item: any, fnc: string) => {
	Object.keys(presetLayouts.value).forEach((ac) => {
		if (fnc === 'push') {
			presetLayouts.value[ac].push({ ...item })
		} else if (fnc === 'filter') {
			presetLayouts.value[ac] = presetLayouts.value[ac].filter(
				(data: any) => data.i !== item.i
			)
		}
	})
	layout.value = presetLayouts.value[pageSize.value]
	if (fnc === 'push')
		nextTick(() => {
			const ac = layout.value.filter((target) => target.i === item.i)[0]
			itemClick(ac)
		})
}

// 布局数据修改后重写布局数据
const moved = (i: string, x: number, y: number) => {
	resetLayout({ i, x, y })
}
const resized = (i: string, h: number, w: number) => {
	resetLayout({ i, h, w })
}
const resetLayout = (item: any) => {
	presetLayouts.value[pageSize.value].forEach((ac: any) => {
		if (ac.i === item.i) {
			Object.assign(ac, item)
			storeTarget.setActiveTarget(ac)
		}
	})
}

const wrapper = ref()
const gridLayout = ref()

function syncMousePosition(event: any) {
	return {
		x: event.originalEvent.clientX,
		y: event.originalEvent.clientY
	}
}

function dragEnd(event: any, type: string) {
	const parentRect = wrapper.value?.getBoundingClientRect()
	// 容器不存在
	if (!parentRect || !gridLayout.value) return
	const { x, y } = syncMousePosition(event)
	const mouseInGrid =
		x > parentRect.left &&
		x < parentRect.right &&
		y > parentRect.top &&
		y < parentRect.bottom
	const _vm_ = event.item._underlying_vm_
	const dragItem = _vm_?.options
	const colWid = parentRect.width / colNum.value
	const mouseX = Math.floor((x - parentRect.left - window.scrollX) / colWid)
	const mouseY = Math.floor(
		(y - parentRect.top - window.scrollY) / (rowHeight.value + margin.value[1])
	)
	console.log('mouse in grid:', mouseX, mouseY)
	// 没有将节点拖拽到容器中
	if (!mouseInGrid) return
	// 如果是拖拽容器则添加容器
	if (type === '1') {
		dragItem.w = store.w
		dragItem.h = store.h
		dragItem.x = mouseX
		dragItem.y = mouseY
		dragItem.i = 'dropId' + new Date().getTime()
		gridLayout.value.dragEvent(
			'dragend',
			dragItem.i,
			dragItem.x,
			dragItem.y,
			dragItem.h,
			dragItem.w,
			dragItem.name
		)
		optLayout(dragItem, 'filter')
		optLayout(
			{
				name: dragItem.name,
				x: dragItem.x,
				y: dragItem.y,
				w: dragItem.w,
				h: dragItem.h,
				i: dragItem.i,
				category: _vm_.category,
				children: []
			},
			'push'
		)

		gridLayout.value.dragEvent(
			'dragend',
			dragItem.i,
			dragItem.x,
			dragItem.y,
			dragItem.h,
			dragItem.w
		)
	} else {
		// 添加节点需要判断是否拖拽到容器组件
		// 是  将组件添加到对应容器
		// 否  创建容器组件后添加到容器组件
		// 获取当前拖入的节点
		let dragInWidget = null
		layout.value.forEach((item) => {
			if (
				mouseX >= item.x &&
				mouseX <= item.x + item.w &&
				mouseY >= item.y &&
				mouseY <= item.y + item.h
			) {
				dragInWidget = item
			}
		})
		if (!dragInWidget) return ElMessage.warning('请拖拽到容器组件中')
		else {
			dragItem.i = 'compId' + new Date().getTime()
			dragItem.category = _vm_.category
			dragInWidget.children.push({ ...dragItem })
			itemClick(dragItem)
		}
	}

	const item = gridLayout.value.getItem(dragItem.i)

	if (!item) return

	try {
		item.wrapper.style.display = ''
	} catch (e) {}
}

const layoutClick = () => {
	storeTarget.clear()
}

const itemClick = (item: any) => {
	storeTarget.setActiveTarget(item)
}

const getData = () => {
	return {
		config: store.getState,
		data: presetLayouts.value
	}
}

const setData = (data: any, type = 'reload') => {
	store.setState(data.config)
	presetLayouts.value = data.data
	if (type === 'reload') layout.value = presetLayouts.value[pageSize.value]
	else Object.assign(layout.value, presetLayouts.value[pageSize.value])
}

const emptyData = () => {
	layout.value = []
	presetLayouts.value = {
		lg: [],
		sm: [],
		xxs: []
	}
	layoutClick()
}

const operationItem = (data: any, type: string) => {
	if (type === 'del') {
		Object.keys(presetLayouts.value).forEach((ac) => {
			presetLayouts.value[ac].forEach((item: any) => {
				item.children.forEach((child: any, index: number) => {
					if (child.i === data.i) {
						item.children.splice(index, 1)
					}
				})
			})
		})
		layout.value = presetLayouts.value[pageSize.value]
		layoutClick()
	}
}

const pushDataToHistory = () => {
	if (!historyStore.isHistory) {
		const data = getData()
		historyStore.addHistory(data)
		historyStore.setIsHistory(false)
	}
}

const layoutUpdated = (layoutData: any) => {
	presetLayouts.value[pageSize.value] = layoutData
}

watch(
	[
		() => store.getRowHeight,
		() => store.colNum,
		() => props.defineConfig.layoutType
	],
	(val, oldVal) => {
		gridReload.value = true
		const CN = val[1][pageSize.value]
		bgStyle.value = {
			'--before-colNum': CN,
			'--before-rowHeight': val[0] + 'px'
		}
		colsConfig.value[pageSize.value] = CN
		const oldCN = oldVal[1] ? oldVal[1][pageSize.value] : CN
		layoutChenged(CN, oldCN)
	},
	{
		immediate: true,
		deep: true
	}
)

watch(
	() => historyStore.nowIndex,
	() => {
		setData(historyStore.getHistory, 'assign')
	}
)

let timeoutId = null
watch(
	() => layout.value,
	() => {
		clearTimeout(timeoutId)
		timeoutId = setTimeout(() => {
			pushDataToHistory()
		}, 500)
	},
	{ deep: true }
)

defineExpose({ dragEnd, getData, emptyData, setData })
</script>

<style lang="scss" scoped>
// .PC-layout {
// }
.PAD-layout {
	margin: 0 auto;
	width: 990px;
	height: calc(100vh - 72px);
	border: 10px solid #495060;
	border-radius: 16px;
	overflow-x: hidden;
	overflow-y: hidden;
}

.H5-layout {
	margin: 0 auto;
	width: 480px;
	height: calc(100vh - 60px);
	border-radius: 8px;
	border: 5px solid #495060;
	overflow-x: hidden;
	overflow-y: hidden;
}

.vgl-layout {
	background: #f1f1f1;
	width: 100%;
	min-height: calc(100vh - 50px);
	--before-colNum: 48;
	--before-rowHeight: 30px;
	// position: static;
	// height: 100% !important;
}

.has-gridlines {
	width: 100%;

	.vgl-layout::before {
		position: absolute;
		width: 100%;
		height: 100%;
		margin: 0;
		content: '';
		background-image: linear-gradient(to right, lightgrey 1px, transparent 1px),
			linear-gradient(to bottom, lightgrey 1px, transparent 1px);
		background-repeat: repeat;
		background-size: calc(100% / var(--before-colNum)) var(--before-rowHeight);
	}
}

:deep(.vgl-item:not(.vgl-item--placeholder)) {
	background-color: #fff;
	border: 1px #d8d8d8 dashed;
}
.grid-item {
	position: relative;
	height: 100%;
	width: 100%;
	border: none;
	display: flex;
	flex-direction: inherit;
	.delete-icon {
		position: absolute;
		right: 4px;
		top: 4px;
		z-index: 30;
		cursor: pointer;
		color: #f57474;
		&:hover {
			color: #ff9c9c;
		}
	}
	.copy-icon {
		position: absolute;
		right: 24px;
		top: 4px;
		z-index: 30;
		cursor: pointer;
		color: #409eff;
		&:hover {
			color: #79bbff;
		}
	}
}
.active-item {
	margin: -1px;
	border: 1px #409eff solid;
}

:deep(.vgl-item--resizing) {
	opacity: 90%;
}

:deep(.vgl-item--static) {
	background-color: #cce;
}

:deep(.vgl-item) {
	position: relative;
	height: 100%;
}
.nodata-tips {
	width: 100%;
	height: 100%;
	color: #999;
	text-align: center;
	font-size: 14px;
	font-weight: 600;
	position: relative;
	.nodata-content {
		position: absolute;
		top: 50%;
		margin-top: -27px;
		text-align: center;
		width: 100%;
	}
	.nodata-icon {
		display: block;
		width: 100%;
		font-size: 24px;
		margin-bottom: 8px;
	}
}
</style>
